package trust

import (
	"crypto"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"strconv"
	"time"

	rfc "WZ_law-api/go-rfc3161"
)

var (
	//url prefix and suffix
	prefix = "http://ets.wotrus.com/tk_59_"
	token  = "_qLqjBDU1kCCQAIU"
)

//ProofTime includes what trust organization issue for us
type ProofTime struct {
	UtcTime      string   `json:"utctime"`
	SerialNumber string   `json:"serial"`
	HashFunc     string   `json:"digalg"`
	HashValue    string   `json:"digest"`
	CaName       string   `json:"caname"`
	CaOrg        []string `json:"caorg"`
}

//NewProofTime apply a trust time to proof our message is really exist
func NewProofTime(nowS string, dat string) (*ProofTime, error) {
	//according data (block) timestamp,calculate url where we post request
	now, err := strconv.ParseInt(nowS, 10, 64)
	if err != nil {
		return nil, err
	}
	//now := time.Now().UTC().Unix()
	url := calUrl(now)
	c := rfc.NewClient(url)

	//generat request according rfc3161 protocol
	dataHash := dataOpt([]byte(dat))
	request, err := rfc.NewTimeStampReq(crypto.SHA256, dataHash)
	if err != nil {

		return nil, err
	}

	//post request to ws server
	response, err := c.Do(request)
	if err != nil {
		fmt.Println("crypto")
		return nil, err
	}
	//read trust time
	inf, err := response.GetTSTInfo()
	if err != nil {
		return nil, err
	}
	cert, err := response.GetSigningCert()
	if err != nil {
		return nil, err
	}
	return &ProofTime{
		UtcTime:      strconv.FormatInt(inf.GenTime.Unix(), 10),
		SerialNumber: hex.EncodeToString(inf.SerialNumber.Bytes()),
		HashFunc:     request.GetHash().String(),
		HashValue:    hex.EncodeToString(dataHash),
		CaName:       cert.Issuer.CommonName,
		CaOrg:        cert.Issuer.Organization,
	}, nil
}

//calUrl show destination where post
func calUrl(t int64) string {
	//url route
	timestamp := calTime(t)
	digest := timestamp + token
	hashFunc := sha1.New()
	hashFunc.Write([]byte(digest))
	src := hashFunc.Sum(nil)
	result := hex.EncodeToString(src)

	//url join
	url := prefix + result

	return url
}

//dataOpt encode data to sha256 hash value
func dataOpt(data []byte) []byte {
	//sha256
	hashFunc := sha256.New()
	hashFunc.Write(data)
	src := hashFunc.Sum(nil)

	return src

}

//calTime parse timestamp to request need
func calTime(t int64) string {
	now := time.Unix(t, 0).UTC()
	y := now.Year() * 1e6
	m := int(now.Month()) * 1e4
	d := now.Day() * 1e2
	h := now.Hour()
	timestamp := y + m + d + h
	return strconv.FormatInt(int64(timestamp), 10)
}
